//-------------------------------------------------------------------------------------
// <copyright file="BizTalkAssembly.cs" company="Microsoft">
//      Copyright (c) 2003 Microsoft Corporation. All rights reserved.
//      THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
//      EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
//      WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// </copyright>
// <summary>
//      An assembly that is deployed in BizTalk.
// </summary>  
//-------------------------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.BizTalk2004.Configuration
{
    #region Using directives

    using System;
    using System.Data;
    using System.Data.SqlClient;
    using System.Collections;
    using System.IO;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Xml.Schema;

    #endregion

    #region Class Comments
    /// <summary>
    /// An assembly that is deployed in BizTalk.
    /// </summary>
    /// <remarks>
    /// To create instances of this class either use the 
    /// <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkAssembly.Deploy"/> method to deploy a new
    /// assembly into BizTalk, or <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkAssembly.Load"/>
    /// method to get details of an existing assembly.
    /// </remarks>
    #endregion
    internal class BizTalkAssembly : BizTalkNonConfigurableEntityBase
    {
        #region Member Variables

        private string culture;
        private string simpleName;
        private bool isSystem;
        private string publicKeyToken;
        private Version version;

        private SchemaCollection schemas;
        private MapCollection maps;
        private OrchestrationCollection orchestrations;
        private PipelineCollection pipelines;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new BizTalk assembly. This is private because instance of this class can only be created
        /// using the static Deploy and Load methods.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> that the map will
        /// belong to.
        /// </param>
        /// <param name="name">
        /// The name of the map.
        /// </param>
        private BizTalkAssembly(BizTalkInstallation installation, string name)
            : base(installation, name)
        {
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the culture that the assembly supports.
        /// </summary>
        /// <value>
        /// The culture that the assembly supports.
        /// </value>
        public string Culture
        {
            get
            {
                return this.culture;
            }
        }

        /// <summary>
        /// Gets the collection of maps contained in this assembly.
        /// </summary>
        /// <value>
        /// A <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.MapCollection"/>.
        /// </value>
        public MapCollection Maps
        {
            get
            {
                if (this.maps == null || this.maps.Count == 0)
                {
                    this.maps = new MapCollection();
                    BtsAssembly actualAssembly = BizTalkAssembly.GetActualAssembly(this.Installation, this.Name, true);
                    foreach (BtsTransform actualMap in actualAssembly.Transforms)
                    {
                        Map configMap = Map.Load(this, actualMap.FullName);
                        this.maps.Add(configMap);
                    }
                }
                return this.maps;
            }
        }

        /// <summary>
        /// Gets the collection of orchestrations contained in this assembly.
        /// </summary>
        /// <value>
        /// A <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.OrchestrationCollection"/>.
        /// </value>
        public OrchestrationCollection Orchestrations
        {
            get
            {
                if (this.orchestrations == null || this.orchestrations.Count == 0)
                {
                    this.orchestrations = new OrchestrationCollection();
                    BtsAssembly actualAssembly = BizTalkAssembly.GetActualAssembly(this.Installation, this.Name, true);
                    foreach (BtsOrchestration actualOrchestration in actualAssembly.Orchestrations)
                    {
                        Orchestration configOrchestration = Orchestration.Load(this, actualOrchestration.FullName);
                        this.orchestrations.Add(configOrchestration);
                    }
                }
                return this.orchestrations;
            }
        }

        /// <summary>
        /// Gets the collection of pipelines contained in this assembly.
        /// </summary>
        /// <value>
        /// A <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.PipelineCollection"/>.
        /// </value>
        public PipelineCollection Pipelines
        {
            get
            {
                if (this.pipelines == null || this.pipelines.Count == 0)
                {
                    this.pipelines = new PipelineCollection();
                    BtsAssembly actualAssembly = BizTalkAssembly.GetActualAssembly(this.Installation, this.Name, true);
                    foreach (BtsPipeline actualPipeline in actualAssembly.Pipelines)
                    {
                        Pipeline configPipeline = Pipeline.Load(this, actualPipeline.FullName);
                        this.pipelines.Add(configPipeline);
                    }
                }
                return this.pipelines;
            }
        }

        /// <summary>
        /// Gets the public key token of the assembly.
        /// </summary>
        /// <value>
        /// The public key token.
        /// </value>
        public string PublicKeyToken
        {
            get
            {
                return this.publicKeyToken;
            }
        }

        /// <summary>
        /// Gets the collection of schemas contained in this assembly.
        /// </summary>
        /// <value>
        /// A <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.SchemaCollection"/>.
        /// </value>
        public SchemaCollection Schemas
        {
            get
            {
                if (this.schemas == null || this.schemas.Count == 0)
                {
                    this.schemas = new SchemaCollection();
                    BtsAssembly actualAssembly = BizTalkAssembly.GetActualAssembly(this.Installation, this.Name, true);
                    foreach (BtsSchema actualSchema in actualAssembly.Schemas)
                    {
                        Schema configSchema = Schema.Load(this, actualSchema.FullName);
                        this.schemas.Add(configSchema);
                    }
                }
                return this.schemas;
            }
        }

        /// <summary>
        /// Gets the simple name of the assembly.
        /// </summary>
        /// <value>
        /// The simple name of the assembly.
        /// </value>
        public string SimpleName
        {
            get
            {
                return this.simpleName;
            }
        }

        /// <summary>
        /// Gets the <see cref="System.Version"/> of the assembly.
        /// </summary>
        /// <value>
        /// A <see cref="System.Version"/>
        /// </value>
        public Version Version
        {
            get
            {
                return this.version;
            }
        }

        #endregion

        #region Static Methods

        /// <summary>
        /// Deploys an assembly into BizTalk.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> that the assembly
        /// will be deployed into.
        /// </param>
        /// <param name="assemblyPath">
        /// The path to the assembly.
        /// </param>
        /// <param name="installInGac">
        /// <b>true</b> to install the assembly into the GAC, or <b>false</b> otherwise.
        /// </param>
        /// <param name="bindingPath">
        /// Path to the assembly binding XML file; this may be <b>null</b>.
        /// </param>
        /// <param name="logPath">
        /// Path to the log file; this may be <b>null</b>.
        /// </param>
        /// <returns>
        /// The deployed <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkAssembly"/>.
        /// </returns>
        public static BizTalkAssembly Deploy(
            BizTalkInstallation installation,
            string assemblyPath,
            bool installInGac,
            string bindingPath,
            string logPath)
        {
            // deploy the assembly
            // this results without throwing an exception if the HRESULT is a success code
            int hresult = DeploymentService.Deploy(
                            installation,
                            assemblyPath,
                            installInGac,
                            bindingPath,
                            logPath);
            Marshal.ThrowExceptionForHR(hresult);

            // load it so we can return it
            AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
            return BizTalkAssembly.Load(installation, assemblyName.FullName);
        }

        /// <summary>
        /// Gets whether an assembly exists in a BizTalk deployment.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> to check.
        /// </param>
        /// <param name="name">
        /// The display name of the assembly.
        /// </param>
        /// <returns>
        /// <b>true</b> is the assembly exists in the deployment, or <b>false</b> otherwise.
        /// </returns>
        public static bool Exists(BizTalkInstallation installation, string name)
        {
            return BizTalkAssembly.GetActualAssembly(installation, name, false) != null;
        }

        /// <summary>
        /// Exports the assembly bindings to an XML file.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> to export the bindings from.
        /// </param>
        /// <param name="assemblyPath">
        /// The path to the assembly.
        /// </param>
        /// <param name="bindingPath">
        /// Path to the output assembly binding XML file.
        /// </param>
        /// <param name="logPath">
        /// Path to the log file; this may be <b>null</b>.
        /// </param>
        public static void ExportBindings(
            BizTalkInstallation installation,
            string assemblyPath,
            string bindingPath,
            string logPath)
        {
            // this results without throwing an exception if the HRESULT is a success code
            int hresult = DeploymentService.ExportBindings(
                installation,
                assemblyPath,
                null,
                null,
                null,
                null,
                bindingPath,
                logPath);
            Marshal.ThrowExceptionForHR(hresult);
        }

        /// <summary>
        /// Exports the assembly bindings to an XML file.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> to export the bindings from.
        /// </param>
        /// <param name="name">
        /// The name of the assembly.
        /// </param>
        /// <param name="version">
        /// The version of the assembly.
        /// </param>
        /// <param name="culture">
        /// The culture of the assembly.
        /// </param>
        /// <param name="publicKeyToken">
        /// The pubkic key token of the assembly.
        /// </param>
        /// <param name="bindingPath">
        /// Path to the output assembly binding XML file.
        /// </param>
        /// <param name="logPath">
        /// Path to the log file; this may be <b>null</b>.
        /// </param>
        public static void ExportBindings(
            BizTalkInstallation installation,
            string name,
            Version version,
            string culture,
            string publicKeyToken,
            string bindingPath,
            string logPath)
        {
            // this results without throwing an exception if the HRESULT is a success code
            int hresult = DeploymentService.ExportBindings(
                installation,
                null,
                name,
                version,
                culture,
                publicKeyToken,
                bindingPath,
                logPath);
            Marshal.ThrowExceptionForHR(hresult);
        }

        /// <summary>
        /// Imports a binding file into the target database.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> to import the bindings from.
        /// </param>
        /// <param name="bindingPath">
        /// Path to the assembly binding XML file.
        /// </param>
        /// <param name="logPath">
        /// Path to the log file; this may be <b>null</b>.
        /// </param>
        public static void ImportBindings(
            BizTalkInstallation installation,
            string bindingPath,
            string logPath)
        {
            int hresult = DeploymentService.ImportBindings(installation, bindingPath, logPath);

            // this results without throwing an exception if the HRESULT is a success code
            Marshal.ThrowExceptionForHR(hresult);
        }

        /// <summary>
        /// Loads details of an assembly deployed in BizTalk.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> that the assembly
        /// is deployed in.
        /// </param>
        /// <param name="name">
        /// The name of the assembly.
        /// </param>
        /// <returns>
        /// A <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkAssembly"/>.
        /// </returns>
        public static BizTalkAssembly Load(BizTalkInstallation installation, string name)
        {
            // load the actual assembly
            BtsAssembly actualAssembly = BizTalkAssembly.GetActualAssembly(installation, name, true);

            // create a new config assembly and set basic properties
            BizTalkAssembly configAssembly = new BizTalkAssembly(installation, name);
            configAssembly.isSystem = actualAssembly.IsSystem;
            configAssembly.simpleName = actualAssembly.Name;
            configAssembly.culture = actualAssembly.Culture;
            configAssembly.version = new Version(actualAssembly.Version);
            configAssembly.publicKeyToken = actualAssembly.PublicKeyToken;

            // return the assembly
            return configAssembly;
        }

        /// <summary>
        /// Undeploys an assembly from BizTalk.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> that the assembly
        /// will be undeployed from.
        /// </param>
        /// <param name="assemblyPath">
        /// The path to the assembly. This may be <b>null</b> if <paramref name="name"/>, <paramref name="version"/>,
        /// <paramref name="culture"/> and <paramref name="publicKeyToken"/> are supplied.
        /// </param>        
        /// <param name="uninstallFromGac">
        /// <b>true</b> to uninstall the assembly from the GAC, or <b>false</b> otherwise.
        /// </param>
        /// <param name="logPath">
        /// Path to the log file; this may be <b>null</b>.
        /// </param>
        public static void Undeploy(
            BizTalkInstallation installation,
            string assemblyPath,
            bool uninstallFromGac,
            string logPath)
        {
            // this results without throwing an exception if the HRESULT is a success code
            int hresult = DeploymentService.Undeploy(
                installation,
                assemblyPath,
                null,
                null,
                null,
                null,
                uninstallFromGac,
                logPath);
            Marshal.ThrowExceptionForHR(hresult);
        }

        /// <summary>
        /// Undeploys an assembly from BizTalk.
        /// </summary>
        /// <param name="installation">
        /// The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> that the assembly
        /// will be undeployed from.
        /// </param>
        /// <param name="name">
        /// The simple name of the assembly. 
        /// </param>
        /// <param name="version">
        /// The version of the assembly.
        /// </param>
        /// <param name="culture">
        /// The culture of the assembly.
        /// </param>
        /// <param name="publicKeyToken">
        /// The pubkic key token of the assembly. 
        /// </param>
        /// <param name="uninstallFromGac">
        /// <b>true</b> to uninstall the assembly from the GAC, or <b>false</b> otherwise.
        /// </param>
        /// <param name="logPath">
        /// Path to the log file; this may be <b>null</b>.
        /// </param>
        public static void Undeploy(
            BizTalkInstallation installation,
            string name,
            Version version,
            string culture,
            string publicKeyToken,
            bool uninstallFromGac,
            string logPath)
        {
            // this results without throwing an exception if the HRESULT is a success code
            int hresult = DeploymentService.Undeploy(
                installation,
                null,
                name,
                version,
                culture,
                publicKeyToken,
                uninstallFromGac,
                logPath);
            Marshal.ThrowExceptionForHR(hresult);
        }               
        #endregion

        #region Methods

        /// <summary>
        /// Exports this assembly's bindings to an XML file.
        /// </summary>
        /// <param name="bindingPath">
        /// Path to the output assembly binding XML file.
        /// </param>
        /// <param name="logPath">
        /// Path to the log file; this may be <b>null</b>.
        /// </param>
        public void ExportBindings(string bindingPath, string logPath)
        {
            BizTalkAssembly.ExportBindings(
                this.Installation,
                this.Name,
                this.version,
                this.culture,
                this.publicKeyToken,
                bindingPath,
                logPath);
        }

        /// <summary>
        /// Undeploys this assembly from BizTalk.
        /// </summary>
        /// <param name="uninstallFromGac">
        /// <b>true</b> to uninstall the assembly from the GAC, or <b>false</b> otherwise.
        /// </param>
        /// <param name="logPath">
        /// Path to the log file; this may be <b>null</b>.
        /// </param>
        public void Undeploy(bool uninstallFromGac, string logPath)
        {
            BizTalkAssembly.Undeploy(
                this.Installation,
                this.simpleName,
                this.version,
                this.culture,
                this.publicKeyToken,
                uninstallFromGac,
                logPath);
        }

        /// <summary>
        /// Gets the actual assembly object that is deployed in BizTalk.
        /// </summary>
        /// <param name="installation">
        /// The BizTalk installation containing the assembly.
        /// </param>
        /// <param name="name">
        /// The display name of the assembly.
        /// </param>
        /// <param name="throwIfNotFound">
        /// <b>true</b> to throw an error if the assembly is not found, or <b>false</b> otherwise.
        /// </param>
        /// <returns>
        /// A BtsBtsAssembly object. 
        /// </returns>
        /// <exception cref="System.InvalidOperationException">
        /// Thrown when <paramref name="throwIfNotFound"/> is <b>true</b> and the assembly does not exist 
        /// in the BizTalk Server installation.
        /// </exception>
        internal static BtsAssembly GetActualAssembly(BizTalkInstallation installation, string name, bool throwIfNotFound)
        {
            // in BizTalk collection the name is just the name of the assembly, not the display name. if there
            // are multiple versions of it deployed then they all have the same name and the collection will
            // just return the first one it comes across that matches. to get around this we will enumerate
            // them all and compare the display name with the one we want to find.
            BtsAssembly actualAssembly = null;
            foreach (BtsAssembly candidateAssembly in installation.CatalogExplorer.Assemblies)
            {
                if (candidateAssembly.DisplayName == name)
                {
                    actualAssembly = candidateAssembly;
                    break;
                }
            }

            if (throwIfNotFound && actualAssembly == null)
            {
                throw new InvalidOperationException("The assembly does not exist in the BizTalk Server installation.");
            }
            return actualAssembly;
        }

        /// <summary>
        /// Gets the actual assembly that this assembly wraps.
        /// </summary>
        /// <returns>
        /// The actual assembly.
        /// </returns>
        internal BtsAssembly GetActualAssembly()
        {
            return BizTalkAssembly.GetActualAssembly(this.Installation, this.Name, true);
        }

        #endregion
    }
}

